package gnss

import (
	"dgo/goutils/utils"
	"encoding/base64"
	"fmt"
	"strings"
)

var (
	NTRIP_HEAD_SPLITER = []byte("\r\n\r\n")
)

type NtripHeadDecoder struct {
	utils.BytesBuilder
}

func NewNtripHeadDecoder() *NtripHeadDecoder {
	rval := &NtripHeadDecoder{}
	return rval
}

/*
*

	-1: DecodeErr
	 0: NeedMore
	 1: DecodeHead
*/
func (this *NtripHeadDecoder) InputByte(data byte) int {
	this.WriteByte(data)
	// 5(GET / OR SOURCE) + 4(\r\n\r\n)
	l := this.Len()
	if l > 9 {
		if this.HasSuffix(NTRIP_HEAD_SPLITER) {
			return 1
		}
	}
	return 0
}

type NtripHead struct {
	Method        string
	Head          map[string]string
	Mp            string // URI
	SourceAuthStr string
	RawText       string // 去掉非法字符
}

func NewNtripHead() *NtripHead {
	rval := &NtripHead{}
	return rval
}

func (this *NtripHead) Reset() {
	this.Method = ""
	this.Mp = ""
	this.SourceAuthStr = ""
	this.RawText = ""
	for k, _ := range this.Head {
		delete(this.Head, k)
	}

}

func (this *NtripHead) CopyFrom(src *NtripHead) {
	this.Mp = src.Mp
	this.Method = src.Method
	this.SourceAuthStr = src.SourceAuthStr
	this.RawText = src.RawText
	if this.Head == nil {
		this.Head = make(map[string]string)
	}
	for k, v := range src.Head {
		this.Head[k] = v
	}
}

func (this *NtripHead) Encode() string {
	var sb utils.BytesBuilder
	if this.Method == "GET" {
		mpstr := this.Mp
		if len(mpstr) > 0 && mpstr[0] != '/' {
			sb.AppendStrs("GET /", this.Mp, " HTTP/1.0\r\n")
		} else {
			sb.AppendStrs("GET ", this.Mp, " HTTP/1.0\r\n")
		}

	} else {
		sb.AppendStrs("SOURCE ", this.SourceAuthStr, " /", this.Mp, "\r\n")
	}

	utils.MapEncode(this.Head, ": ", "\r\n", false, &sb)
	sb.AppendStr("\r\n\r\n")
	return sb.String()
}

/*
*
GET <mountpoint> HTTP/1.0 <CR><LF>
GET /BUCU0 HTTP/1.0

SOURCE <password> <mountpoint> <CR><LF>
SOURCE letmein /Mountpoint
*/
func (this *NtripHead) innerDecodeHead(str string) bool {
	strs := strings.Split(str, " ")
	this.Method = strs[0]
	if this.Method == "GET" {
		this.Mp = strings.TrimPrefix(strs[1], "/")
		return true
	}
	if this.Method == "SOURCE" {
		if len(strs) == 2 {
			this.SourceAuthStr = ""
			this.Mp = strings.TrimPrefix(strs[1], "/")
			return true
		}

		if len(strs) == 3 {
			this.SourceAuthStr = strs[1]
			this.Mp = strings.TrimPrefix(strs[2], "/")
			return true
		}
	}
	return false
}

func (this *NtripHead) ExtractBasicAuthRawStr() string {
	if len(this.Head) == 0 {
		return ""
	}
	str := this.Head["Authorization"]
	str = strings.TrimPrefix(str, "Basic ")
	str = utils.Trim(str)
	return str
}

func (this *NtripHead) SetUserPass(user, pass string) {
	if this.Head == nil {
		this.Head = make(map[string]string)
	}
	str := user + ":" + pass
	authstr := base64.StdEncoding.EncodeToString([]byte(str))
	this.Head["Authorization"] = fmt.Sprintf("Basic %s", authstr)
}

func (this *NtripHead) ExtractHead(id string) string {
	return this.Head[id]
}

func (this *NtripHead) ExtractUserAgent() string {
	str := this.Head["user-agent"]
	if len(str) == 0 {
		str = this.Head["User-Agent"]
	}
	str = utils.Trim(strings.TrimPrefix(str, "NTRIP"))
	return str
}

/*
X-Forwarded-For: client, proxy1, proxy2
*/
func (this *NtripHead) GetClientIP(defip string) string {
	str := this.GetXForwaredFor()
	if len(str) == 0 {
		return defip
	} else {
		idx := strings.IndexByte(str, ',')
		if idx == -1 {
			return str
		} else {
			return string([]byte(str)[:idx])
		}
	}
}

/*
*

从上面大家也看出来了，因为有了各种代理，才会导致 REMOTE_ADDR 这个全局变量产生了一定的歧义，为了让 Web 服务器获取到真实的客户端 IP，X-Forwarded-For 出现了，这个协议头也是由 Squid 起草的（Squid 应该是最早的代理软件之一）。
client 表示用户的真实 IP，每经过一次代理服务器，代理服务器会在这个头增加用户的 IP（有点拗口）。

注意最后一个代理服务器请求 Web 服务器的时候是不会将自己的 IP 附加到 X-Forwarded-For 头上的，最后一个代理服务器的 IP 地址应该通过$_SERVER['REMOTE_ADDR']获取。
举个例子：
用户的 IP 为（A）,分别经过两个代理服务器（B，C），最后到达 Web 服务器，那么Web 服务器接收到的 X-Forwarded-For 就是 A,B。
*/
func (this *NtripHead) ExtractXForwaredForEx(clientip string) string {
	str := this.GetXForwaredFor()
	if len(str) == 0 {
		str = clientip
	} else {
		str = fmt.Sprintf("%s,%s", str, clientip)
	}
	return str
}

/*
注意最后一个代理服务器请求 Web 服务器的时候是不会将自己的 IP 附加到 X-Forwarded-For 头上的，最后一个代理服务器的 IP 地址应该通过$_SERVER['REMOTE_ADDR']获取。
举个例子：
用户的 IP 为（A）,分别经过两个代理服务器（B，C），最后到达 Web 服务器，那么Web 服务器接收到的 X-Forwarded-For 就是 A,B。
*/
func (this *NtripHead) SetXForwaredFor(v string) {
	this.Head["X-Forwarded-For"] = v
}

/*
X-Forwarded-For: client, proxy1, proxy2
*/
func (this *NtripHead) GetXForwaredFor() string {
	str := this.Head["X-Forwarded-For"]
	if len(str) == 0 {
		str = this.Head["x-forwarded-for"]
	}
	return str
}

func (this *NtripHead) ExtractBasicAuth() (user, pass string, err error) {
	str := this.ExtractBasicAuthRawStr()

	decodeBytes, e1 := utils.Base64Decode(str)
	//if e1 != nil {
	//	decodeBytes, e1 = base64.StdEncoding.DecodeString(str + "==")
	//	if e1 != nil {
	//		err = e1
	//		return
	//	}
	//}
	if len(decodeBytes) > 0 {
		str = string(decodeBytes)
		user, pass = utils.Split2Str(str, ":")
		return
	} else if e1 != nil {
		err = e1
		return
	}
	return
}

func (this *NtripHead) GetRequestType() uint8 {
	if this.Method == "GET" {
		return TYPE_NTRIPCLIENT
	}
	if this.Method == "SOURCE" {
		return TYPE_NTRIPSERVER
	}
	return TYPE_UNKOWN
}

func (this *NtripHead) innerDecodeLine(str string) {
	if len(str) == 0 {
		return
	}
	s1, s2 := utils.Split2Str(str, ":")
	this.Head[s1] = utils.Trim(s2)
}

func (this *NtripHead) ParseText(str string) bool {
	str = utils.DelNonChineseCharEx(str, ' ') // 去掉非法字符
	strs := strings.Split(str, "\r\n")
	if len(strs) == 0 {
		return false
	}

	this.Head = make(map[string]string)
	for i := 0; i < len(strs); i++ {
		if i == 0 {
			if !this.innerDecodeHead(strs[0]) {
				return false
			}
			this.RawText = str
		} else {
			this.innerDecodeLine(strs[i])
		}
	}
	return true
}
